<?php

namespace app\yue\home;

// use GuzzleHttp\Client;
use GatewayClient\Gateway;
use WxDecrypt\WXBizDataCrypt;

class Auth extends Common
{
    protected $uid;
    protected $member_info;

    public function _initialize()
    {
        parent::_initialize();

        if ($this->request->action() != 'login') {
            $session_id = $this->request->header('session_id');
            // cache($session_id, null);
            $res        = cache($session_id);
            if (!isset($res['uid'])) {
                json([
                    'err' => 2,
                    'msg' => 'invalid session_id',
                ])->send();
                exit;
            }

            $this->uid         = $res['uid'];
            $this->member_info = $res;

            // websocket bind
            if ($client_id = input('client_id')) {
                // client_id与uid绑定
                Gateway::bindUid($client_id, $this->uid);
                // 加入某个群组（可调用多次加入多个群组）
                $gid = input('gid/d') and Gateway::joinGroup($client_id, $gid);
            }
        }

    }

    public function index()
    {
        return json([
            'err' => 0,
            'msg' => 'bind success',
        ]);
    }

    public function getGid()
    {
        $encryptedData = input('encryptedData');
        $iv            = input('iv');

        $pc      = new WXBizDataCrypt($this->appid, $this->member_info['session_key']);
        $errCode = $pc->decryptData($encryptedData, $iv, $gid);
        // "{"openGId":"GEK4O0YfBhUYFrFlGvf0yZUMbsBE","watermark":{"timestamp":1502785336,"appid":"wx08e01b5466f1cca0"}}"
        trace($encryptedData.'/'.$iv, 'error');
        trace($errCode, 'error');
        // return json([
        //     'err' => 0,
        //     'gid' => json_decode($gid)->openGId,
        //     'msg' => 'success',
        // ]);

        $gid = $errCode ? '' : json_decode($gid)->openGId;
        
        return $gid;
    }

    public function login()
    {
        $code          = input('code');
        $encryptedData = input('encryptedData');
        $iv            = input('iv');
        $rawData       = input('rawData');
        $signature     = input('signature');

        $res = $this->curl("https://api.weixin.qq.com/sns/jscode2session?appid={$this->appid}&secret={$this->secret}&js_code={$code}&grant_type=authorization_code");
        $res = json_decode($res, true);

        trace(json_encode($res), 'error');

        $signature_server = sha1($rawData . $res['session_key']);
        if ($signature != $signature_server) {
            return json([
                'err' => 1,
                'msg' => 'invalid signature',
            ]);
        }

        $pc      = new WXBizDataCrypt($this->appid, $res['session_key']);
        $errCode = $pc->decryptData($encryptedData, $iv, $member_info);
        if ($errCode == 0) {
            $member_info = json_decode($member_info, true);
            if ($member_info['watermark']['appid'] != $this->appid) {
                return json([
                    'err' => 1,
                    'msg' => 'invalid appid',
                ]);
            }

            if (abs($member_info['watermark']['timestamp'] - time()) > 60) {
                return json([
                    'err' => 1,
                    'msg' => 'invalid timestamp',
                ]);
            }

            // reduce the size of avatar picture
            $member_info['avatarUrl'] = \substr_replace($member_info['avatarUrl'], 132, -1);
            $uid                      = $this->addMember($member_info);
            $res['uid']               = $uid;
            $res                      = array_merge($res, $member_info);

            $session_id = self::randomStr(128);
            cache($session_id, $res, $res['expires_in'] - 200);
        } else {
            trace('decrypt:' . $errCode, 'error');
            return json([
                'err' => 1,
                'msg' => $errCode,
            ]);
        }

        return json([
            'err'        => 0,
            'session_id' => $session_id,
            'msg'        => 'login successfully',
        ]);
    }

    protected function setSession($key, $value, $time = 86400)
    {
        $session_id  = $this->request->header('session_id');
        $cache_value = cache($session_id);
        if (\is_array($cache_value)) {
            $cache_value[$key] = $value;
        }
        cache($session_id, $cache_value, $time);
    }

    protected function addMember($member_info)
    {
        $ip                = $this->request->ip();
        $member_info['ip'] = $ip;

        $member = model('yue_member');
        if ($_member = $member->where('openId', $member_info['openId'])->find()) {
            $_member->save($member_info);
            $uid = $_member->id;
        } else {
            $member->save($member_info);
            $uid = $member->id;
        }
        return $uid;
    }

    /**
     * Generate a random string, using a cryptographically secure
     * pseudorandom number generator (random_int)
     *
     * For PHP 7, random_int is a PHP core function
     * For PHP 5.x, depends on https://github.com/paragonie/random_compat
     *
     * @param int $length      How many characters do we want?
     * @param string $keyspace A string of all possible characters
     *                         to select from
     * @return string
     */
    protected static function randomStr($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
    {
        $str = '';
        $max = mb_strlen($keyspace, '8bit') - 1;
        for ($i = 0; $i < $length; ++$i) {
            $str .= $keyspace[random_int(0, $max)];
        }
        return $str;
    }
}
